package main

import (
	"context"
	"embed"
	"encoding/json"
	"feishup2pclient/api"
	"feishup2pclient/data"
	"runtime"
	"unsafe"

	//"feishup2pclient/fire"
	"feishup2pclient/msg"
	"feishup2pclient/utils"

	//"feishup2pclient/isadmin"
	//"feishup2pclient/wg"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/labstack/gommon/log"
	"github.com/wailsapp/wails/v2"
	"github.com/wailsapp/wails/v2/pkg/options"
	"github.com/wailsapp/wails/v2/pkg/options/assetserver"
	"golang.org/x/sys/windows"
)

type TransmitParams struct {
	Operate        string `json:"operate"`
	EncryptionData string `json:"encryptionData"`
}

type P2PSocketParams struct {
	MType  string           `json:"mType"`
	IfInfo P2PInterfaceInfo `json:"ifInfo,omitempty"`
	Peers  []P2PPeerInfo    `json:"peers,omitempty"`
}

type P2PPeerInfo struct {
	Name  string `json:"name,omitempty"`
	PuK   string `json:"puK,omitempty"`
	Ip    string `json:"ip,omitempty"`
	AllIp string `json:"allIp,omitempty"`
	Mode  string `json:"mode,omitempty"` //p2p relay
	IIp   string `json:"IIp,omitempty"`
	On    string `json:"on,omitempty"` //系统名称
	Cp    string `json:"cp,omitempty"` //控制端口
}
type P2PInterfaceInfo struct {
	P2PPeerInfo
	PrK string `json:"prK,omitempty"`
}

type Connetion struct {
	con   *websocket.Conn
	mutex sync.Mutex
}

var (
	tokenStr = flag.String("t", "", "服务端分配的P2P token")
	version  = flag.Bool("v", false, "show version")
	birdPath = flag.String("birdPath", "/etc/bird.conf", "bird 配置文件目录")
	aesKey   = flag.String("aesKey", "", "aes密钥")
	// wgAddr   = flag.String("d", "0.0.0.0", "wg网卡address")
	// apiPort             = flag.Int("apiPort", 0, "api端口")
	runBird = flag.String("ospf", "", "是否启动ospf Y启动，N不启动,默认不启动")
	// networkCard         = flag.String("networkCard", "", "网卡名称")
	clientVersion       = "0.0.1"
	token               data.Token
	wgName              string
	serverConn          *Connetion
	pongWait            = 60 * time.Second
	pingPeriod          = (pongWait * 8) / 10
	writeWait           = 10 * time.Second
	buildV              = "default"
	interfacePrivateKey = ""
	interfaceIp         = ""
	SrcJson             string
)

//go:embed all:frontend/dist
var assets embed.FS

func _main() {
	// log.Infof("build time %s", buildV)
	//go app_main();//图像界面
	app := NewApp()
	app.Test_set_value("aaaaa")
	// log.Infof("tokenStr %s", *tokenStr)
	if flag.Parse(); !flag.Parsed() {
		// log.Errorf(`参数解析失败`)
		return
	}
	// if len(*networkCard) == 0 {
	// 	*networkCard = os.Getenv("networkCard")
	// 	if len(*networkCard) == 0 {
	// 		fmt.Printf(`networkCard不能为空`)
	// 		return
	// 	}
	// }
	if *version {
		// log.Info(clientVersion)
	}
	if len(*tokenStr) == 0 {
		*tokenStr = os.Getenv("t")
		if len(*tokenStr) == 0 {
			fmt.Printf(`token不能为空`)
			return
		}
	}
	utils.InitAes(*aesKey)
	srcJson, err := utils.AesDecrypt(*tokenStr)
	if err != nil {
		fmt.Printf("token解析失败:%v\n", err)
		return
	}
	token = data.Token{}
	err = json.Unmarshal([]byte(srcJson), &token)
	if err != nil {
		fmt.Printf("token格式错误:%v\n", err)
		return
	}
	if len(token.Server) == 0 {
		fmt.Printf("服务端地址为空:%v\n", err)
		return
	}
	if len(token.CIp) == 0 {
		fmt.Printf("客户端IP为空:%v\n", err)
		return
	}
	if len(token.Cn) == 0 {
		fmt.Printf("客户端网卡名称为空:%v\n", err)
		return
	}
	if len(*runBird) == 0 {
		*runBird = os.Getenv("ospf")
	}
	// log.Infof("ospf:" + *runBird)
	// p2p.StartP2P(token.Cn, token.CIp)
	go api.InitApi()
	//socket.StartSocket(token)

	// time.Sleep(time.Second * 1)
	// err, osName := wg.GetOsName()
	// if err != nil {
	// 	log.Infof(err.Error())
	// 	return
	// }
	// data.SelfOsName = osName
	// err = wg.AddInterface(token.Cn)
	// if err != nil {
	// 	log.Infof(err.Error())
	// 	return
	// }
	// log.Infof("wg[%s]创建成功", wgName)
	// if runtime.GOOS != "windows" {
	// 	err = wg.ClearIptables(wgName)
	// 	if err != nil {
	// 		log.Infof(err.Error())
	// 		return
	// 	}
	// 	log.Infof("清除iptables成功")
	// 	err = wg.AddIptables(wgName, *networkCard)
	// 	if err != nil {
	// 		log.Infof(err.Error())
	// 		return
	// 	}
	// 	log.Infof("添加iptables成功")
	// 	if *runBird == `Y` || *runBird == `y` {
	// 		err = wg.WriteBird(wgName, *birdPath)
	// 		if err != nil {
	// 			log.Infof(err.Error())
	// 			//return
	// 		} else {
	// 			log.Infof("bird 启动成功")
	// 		}
	// 	}
	// }
	// port, err := wg.GetIfaceListenPortString(wgName)
	// if err != nil {
	// 	log.Infof(err.Error())
	// 	return
	// }
	// go checkPeerNormalStatus()
	// startWs(port, osName)
}

var Ctxa context.Context

func isAdminWindows() bool {
	_, err := os.Open("\\\\.\\PHYSICALDRIVE0")
	return err == nil
}

var (
	modUser32 = windows.NewLazySystemDLL("user32.dll")

	procMessageBox = modUser32.NewProc("MessageBoxW")
)

func messageBox(title, message string, typ uintptr) (int, error) {
	ret, _, callErr := procMessageBox.Call(
		uintptr(unsafe.Pointer(nil)),
		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(message))),
		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(title))),
		typ,
	)
	return int(ret), callErr
}
func main() {
	var isAdmin bool
	// recoverFunc := func(err interface{}) {
	// 	if err != nil {
	// 		fmt.Println("发生了错误：", err)
	// 		msg.PanicCheck(err.Error())
	// 	} else {
	// 		msg.PanicCheck(err.Error())
	// 	}
	// }

	// // 设置全局异常处理器
	// defer recoverFunc()

	switch runtime.GOOS {
	case "windows":
		isAdmin = isAdminWindows()
	default:
		isAdmin = os.Geteuid() == 0
	}

	if isAdmin {
		wailsCreate()
	} else {
		switch runtime.GOOS {
		case "windows":
			messageBox("警告", "请以管理员权限运行程序!", windows.MB_OK|windows.MB_ICONWARNING)
		}
		msg.ErrCheck("无管理员权限")
		panic("无管理员权限")
	}
}

// u3vs9AxkjTvi2bRSNWAmjv1V4cyh8m3ep/CNjDHQWck0r68ixlXFtuff3/OTvzwQRLc3RSrhd56RirbqHmD/HY/zLSdAoYZBd9iD9z5jziEdNuEfC7IINTw91BIV1dTVwmYVJFCranVuO2jirWngLSmrTDIav8kgFEoZ35XAUd8=
func wailsCreate() {
	// 创建应用程序结构的实例
	app := NewApp()
	getdata := NewGetData()
	main_app := NewMain_App()
	mini := NewMini()
	//消息通道实例化
	todo_app := NewTodos()
	setData := NewSetData()
	TunStatus := NewTunStatus()

	nat := NewNatPage()
	//firewall
	// fire.CloseFirewall()
	// fire.StartFirewall()
	go todo_app.Chana()
	err := wails.Run(&options.App{
		Title:             "飞鼠",
		Width:             1024,
		Height:            768,
		MinWidth:          600,
		MinHeight:         400,
		HideWindowOnClose: true,
		AssetServer: &assetserver.Options{
			Assets: assets,
		},
		BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 1},
		OnStartup: func(ctx context.Context) {
			Ctxa = ctx
			mini.startup(ctx)
			app.startup(ctx)
			main_app.startup(ctx)
			//设置数据初始化
			setData.startup(ctx)
			//获取数据初始化
			getdata.startup(ctx)
			nat.startup(ctx)
			//tun 状态初始化
			TunStatus.startup(ctx)

		},
		Bind: []interface{}{
			nat,
			app,
			main_app,
			todo_app,
			setData,
			getdata,
			TunStatus,
			mini,
		},
	})

	app.Test_value()

	if err != nil {
		println("Error:", err.Error())
	}
}

func startWs(port, osName string) {
	u := url.URL{Scheme: "ws", Host: token.Server, Path: "/p2pWs"}

	// log.Infof("p2p socket 尝试连接:%s", u.String())
	msg.SendMessage(fmt.Sprintf("p2p socket 尝试连接:%s", u.String()))

	header := http.Header{}
	header.Add(`p2p-cid`, token.Cid)
	header.Add(`p2p-aid`, token.Aid)
	header.Add(`p2p-pt`, port)
	header.Add(`p2p-pt`, port)
	header.Add(`p2p-on`, osName)
	header.Add(`p2p-cp`, fmt.Sprintf("%d", data.ControlPort))
	c, _, err := websocket.DefaultDialer.Dial(u.String(), header)
	if err != nil {
		// log.Infof("p2p socket 连接[%s]失败:%s", u.String(), err.Error())
		time.Sleep(time.Second * 10)
		startWs(port, osName)
		return
	}
	serverConn = &Connetion{con: c}
	// log.Infof("p2p socket 连接服务成功:%s", u.String())
	msg.SendMessage(fmt.Sprintf("p2p socket 连接服务成功:%s", u.String()))
	go func() {
		for {
			if serverConn == nil {
				return
			}
			c.SetReadDeadline(time.Now().Add(pongWait))
			transmitParams := TransmitParams{}
			err := c.ReadJSON(&transmitParams)
			if err != nil {
				// log.Infof("p2p socket 断开连接 接收server json失败:%s", err)
				msg.SendMessage(fmt.Sprintf("p2p socket 断开连接 接收server json失败:%s", err))
				c.Close()
				serverConn = nil
				break
			}
			// log.Infof(`接收server消息原始数据[%+v]`, transmitParams)
			params, err := decrypt(transmitParams.EncryptionData, utils.DefaultAesKey)
			if err != nil {
				// log.Infof("p2p socket 接收server消息再次解密失败:%v", err)
				msg.SendMessage(fmt.Sprintf("p2p socket 接收server消息再次解密失败:%s", err))
				continue
			}
			str, err := json.Marshal(params)
			if err != nil {
				msg.SendMessage(fmt.Sprintf("p2p socket 接收server消息json[%s]", str))
				// log.Infof("p2p socket 接收server消息json[%s]", str)
			} else {
				msg.SendMessage(fmt.Sprintf("p2p socket 接收server消息[%+v]", params))
				// log.Infof("p2p socket 接收server消息[%+v]", params)
			}
			switch params.MType {
			case `peer`:
				// handlerPeer(params)
			}
		}
	}()
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		// log.Infof(`conn关闭%d`, token.Cid)
		ticker.Stop()
		c.Close()
		serverConn = nil
		time.Sleep(time.Second * 10)
		startWs(port, osName)
	}()
	for range ticker.C {
		if err := SendJsonToMaster(P2PSocketParams{MType: `ping`}, true); err != nil {
			// log.Infof(`p2p socket ping server 失败:%s`, err.Error())
			msg.SendMessage(fmt.Sprintf(`p2p socket ping server 失败:%s`, err.Error()))
			break
		}
	}
}

// func handlerPeer(params *P2PSocketParams) {
// 	if len(params.IfInfo.PrK) == 0 {
// 		log.Infof("未收到interface信息")
// 		return
// 	}
// 	if interfacePrivateKey != params.IfInfo.PrK {
// 		data.SelfIp = params.IfInfo.Ip
// 		data.SelfClientName = params.IfInfo.Name
// 		interfacePrivateKey = params.IfInfo.PrK
// 		if err := wg.SetPrivateKey(wgName, params.IfInfo.PrK, params.IfInfo.PuK); err != nil {
// 			log.Infof(err.Error())
// 			return
// 		}
// 	}
// 	if interfaceIp != params.IfInfo.Ip {
// 		interfaceIp = params.IfInfo.Ip
// 		if err := wg.SetInterfaceIp(wgName, params.IfInfo.Ip); err != nil {
// 			log.Infof(err.Error())
// 			return
// 		}
// 		if err := wg.StartInterface(wgName); err != nil {
// 			log.Infof(err.Error())
// 			return
// 		}
// 	}
// 	log.Debugf("处理wg [%s] peers", wgName)
// 	//远端peer信息
// 	rPeerMap := make(map[string]P2PPeerInfo)
// 	for _, peer := range params.Peers {
// 		rPeerMap[peer.PuK] = peer
// 	}
// 	//本地peer信息
// 	lPeers, err := wg.GetPeers(wgName)
// 	if err != nil {
// 		log.Infof(err.Error())
// 		return
// 	}
// 	needCheck := false
// 	for _, lPeer := range lPeers {
// 		//本地和远程有则直接更新ip
// 		if _, ok := rPeerMap[lPeer]; ok {
// 			// p := data.LocalPeers[lPeer]
// 			//ip有变化才更新
// 			// if rPeerMap[lPeer].Ip != p.Ip {
// 			// 	if err := wg.SetPeerEndpointNew(wgName, lPeer, rPeerMap[lPeer].Ip); err != nil {
// 			// 		log.Infof("更新peer[%s]endpoint信息失败:%s", lPeer, err.Error())
// 			// 	} else {
// 			// 		log.Infof("更新peer[%s]信息成功,endpoint[%s]", lPeer, rPeerMap[lPeer].Ip)
// 			// 		p.ConfigUpdateTime = time.Now()
// 			// 		p.Ip = rPeerMap[lPeer].Ip
// 			// 		p.Mode = rPeerMap[lPeer].Mode
// 			// 		p.Status = 1
// 			// 		needCheck = true
// 			// 	}
// 			// }
// 			delete(rPeerMap, lPeer)
// 		} else {
// 			//本地有远程没有则删除peer
// 			if err := wg.DelPeer(wgName, lPeer); err != nil {
// 				log.Infof(err.Error())
// 			} else {
// 				log.Infof("删除peer[%s]信息成功", lPeer)
// 				p := data.LocalPeers[lPeer]
// 				p.ConfigDelTime = time.Now()
// 				p.Status = 4
// 			}
// 		}
// 	}
// 	//远程有，本地没有则新增peer
// 	for _, rPeer := range rPeerMap {
// 		if err := wg.AddPeer(wgName, rPeer.PuK, rPeer.Ip, rPeer.AllIp); err != nil {
// 			log.Infof(err.Error())
// 		} else {
// 			log.Infof("添加peer[%s]信息成功,endpoint[%s]", rPeer.PuK, rPeer.Ip)
// 			if err := wg.SetPersistentKeepalive(wgName, rPeer.PuK); err != nil {
// 				log.Infof(err.Error())
// 			}
// 			data.LocalPeers[rPeer.PuK] = &data.LocalPeer{
// 				Name: rPeer.Name,
// 				// PublicKey:     rPeer.PuK,
// 				Status: 1,
// 				Mode:   rPeer.Mode,
// 				// Ip:            rPeer.Ip,
// 				InnerIp:       rPeer.IIp,
// 				ConfigAddTime: time.Now(),
// 				OsName:        rPeer.On,
// 				ControlPort:   rPeer.Cp,
// 			}
// 			needCheck = true
// 		}
// 	}
// 	if needCheck {
// 		utils.DelayExe(time.Second*1, func() {
// 			// go checkInitPeerStatus(55)
// 		})
// 	}
// }

// func checkInitPeerStatus(out int) {
// 	count := 0
// 	for {
// 		select {
// 		case <-time.Tick(time.Second * 1):
// 			fails := make([]P2PPeerInfo, 0)
// 			count += 1
// 			for _, p := range data.LocalPeers {
// 				if p.Status == 1 {
// 					if err := utils.DoPost(p.InnerIp, p.ControlPort); err != nil {
// 						log.Infof("请求失败：%s", err.Error())
// 						p.FailCount = p.FailCount + 1
// 						if p.FailCount >= 50 {
// 							//已配置状态失败50次
// 							p.Status = 3
// 							p.FailCount = 0
// 							log.Infof("[%s]上报失败", p.InnerIp)
// 							// fails = append(fails, P2PPeerInfo{PuK: p.PublicKey})
// 						}
// 					} else {
// 						p.Status = 2
// 						p.FailCount = 0
// 						log.Infof("[%s]改为连接成功", p.InnerIp)
// 					}
// 				}
// 			}
// 			if len(fails) == 0 {
// 				continue
// 			}
// 			if err := SendJsonToMaster(P2PSocketParams{MType: `fails`, Peers: fails}, true); err != nil {
// 				log.Infof("上送连接失败信息失败:%s", err.Error())
// 			}
// 			if count == out {
// 				return
// 			}
// 		}
// 	}
// }

// func checkPeerNormalStatus() {
// 	for {
// 		select {
// 		case <-time.Tick(time.Second * 60):
// 			fails := make([]P2PPeerInfo, 0)
// 			for _, p := range data.LocalPeers {
// 				if p.Status == 2 {
// 					if err := utils.DoPost(p.InnerIp, p.ControlPort); err != nil {
// 						p.FailCount = p.FailCount + 1
// 						if p.FailCount >= 4 {
// 							//连接成功状态失败4次转为中继
// 							p.Status = 3
// 							p.FailCount = 0
// 							log.Infof("[%s]上报失败", p.InnerIp)
// 							// fails = append(fails, P2PPeerInfo{PuK: p.PublicKey})
// 						}
// 					}
// 				}
// 			}
// 			if len(fails) == 0 {
// 				continue
// 			}
// 			if err := SendJsonToMaster(P2PSocketParams{MType: `fails`, Peers: fails}, true); err != nil {
// 				log.Infof("上送连接失败信息失败:%s", err.Error())
// 			}
// 		}
// 	}

// }

func decrypt(encryptStr, key string) (*P2PSocketParams, error) {
	if len(encryptStr) != 0 {
		jsonStr, err := utils.AesDecryptByKey(encryptStr, key)
		if err != nil {
			// log.Infof("p2p socket 解密失败:%s", err)
			return nil, err
		}
		params := P2PSocketParams{}
		err = json.Unmarshal([]byte(jsonStr), &params)
		if err != nil {
			// log.Infof("p2p socket 解密后[%s]转json失败:%s", []byte(jsonStr), err)
			return nil, err
		}
		return &params, nil
	}
	return nil, nil
}

func SendJsonToMaster(data P2PSocketParams, logSw bool) error {
	if serverConn == nil {
		return fmt.Errorf(`与server未建立socket连接`)
	}
	enData, err := encryptionDataByP2p(utils.DefaultAesKey, data)
	if err != nil {
		return err
	}
	serverConn.con.SetWriteDeadline(time.Now().Add(writeWait))
	serverConn.mutex.Lock()
	err = serverConn.con.WriteJSON(&enData)
	serverConn.mutex.Unlock()
	if err != nil {
		return fmt.Errorf(`发送json失败:%s`, err.Error())
	}
	if logSw {
		// log.Infof(`socket 发送json成功,原始数据[%+v]`, data)
	}
	return nil
}

func encryptionDataByP2p(key string, data P2PSocketParams) (interface{}, error) {
	if len(key) != 0 {
		str, err := json.Marshal(data)
		if err != nil {
			log.Infof(`p2p socket 发送json 对象转json失败:%s`, err.Error())
			return nil, err
		}
		encryptStr, err := utils.AesEncryptByKey(string(str), key)
		if err != nil {
			log.Infof(`p2p socket 发送json 数据加密失败:%s`, err.Error())
			return nil, err
		}
		return TransmitParams{EncryptionData: encryptStr}, nil
	}
	return data, nil
}
